package com.errol.batchprocessor.batchprocessor.advisorimpl.batchsplitter;

import com.renjia.entity.AbstractImportBatch;
import com.renjia.service.generic.middleware.batchprocessor.bo.ThreadPoolStatusBO;
import com.renjia.service.generic.middleware.batchprocessor.payload.AbstractBatchPayload;
import com.renjia.service.generic.middleware.batchprocessor.payload.AbstractPiecePayload;
import com.renjia.service.generic.middleware.batchprocessor.payload.AbstractSinglePayload;
import org.springframework.lang.NonNull;

import java.util.ArrayList;
import java.util.List;

/**
 * 批次分片算法
 *
 * @author zhang xiao bin
 * @version v1.0
 * @date 2021/03/07
 * @since v5.0.5
 **/
public interface BatchSplitter<IE extends AbstractImportBatch, AT extends Enum<?>, BE, SE, BP extends AbstractBatchPayload<IE, AT, BE, SE>, PP extends AbstractPiecePayload<SE, SP>, SP extends AbstractSinglePayload<SE>> {

    /**
     * 批次分片算法接口
     *
     * @param batchPayload        批次数据
     * @param threadPoolStatus    线程池状态
     * @param batchSplitterHelper 批次添加到批处理器的扩展点
     * @return 批次的分片列表
     */
    List<PP> doSplit(@NonNull BP batchPayload, @NonNull ThreadPoolStatusBO threadPoolStatus, @NonNull BatchSplitterHelper<IE, AT, BE, SE, BP, PP, SP> batchSplitterHelper);

    /**
     * 以确定的分片数，平均（约等于）拆分批次，最后一个分片可能少几条
     *
     * @param batchSize           批次中总的记录条数
     * @param pieceCount          分片数
     * @param batchPayload        批次数据
     * @param batchSplitterHelper 分片策略 helper
     * @return List PP
     */
    default List<PP> doSplitByPieceCount(int batchSize, int pieceCount, @NonNull BP batchPayload, @NonNull BatchSplitterHelper<IE, AT, BE, SE, BP, PP, SP> batchSplitterHelper) {
        // 批次记录条数数量如果不是整数，最后一个线程会少几条，10条以内
        int step = (int) Math.ceil(batchSize * 1.0 / pieceCount);
        int start = 0;
        List<PP> pps = new ArrayList<>();
        while (start < batchSize) {
            pps.add(batchSplitterHelper.newPiecePayload(batchPayload.getSingleEntityList().subList(start, (start = Math.min(start + step, batchSize)))));
        }
        return pps;
    }
}
